<?php

namespace App\Library\Freeker;

use App\Library\FeiShu\SendFs;
use App\Models\Common\ConfigModel;
use App\Models\FeishuCallingCard\FeishuCallingCard;
use App\Models\FeishuCallingCard\FeishuCallingCardFranchiseeClue;
use App\Models\FeishuCallingCard\FeishuCallingCardInvestmentEmployeeModel;
use App\Service\BaseService;
use App\Service\CallingCards\ConfigService;
use App\Service\CallingCards\XiaokeService;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

/**
 * 销氪
 */
class FreekerApi extends BaseService
{
    const CLIENT_ID      = '32552B87381A52BA8433E042CAD93AE9';
    const CLIENT_SECRET  = '4F5340CBC0F2D2215F6925079A0879DE';
    const DEFAULT_WID_ID = 2883462990;

    const ACCESS_TOKEN = 'FREEKER_ACCESS_TOKEN';

    /**
     * 创建线索
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function createClue(
        string $customerName,
        string $customerPhone,
        string $salesID,
        string $salesName,
        array  $area,
        string $departmentName,
        string $from = '夸父名片',
        string $remark = '',
        string $interactiveChannel = '夸父名片',
        string $invitorMobile = ''
    ): array
    {
        if (config('app.env') == 'prod' || config('app.env') == 'pre') {
            $remarkPrefix = '';
        } else {
            $remarkPrefix = '测试环境请忽略 ';
        }

        $areaCode = $area['city_code'] ?? '';
        $address  = '';
        if (!strlen($areaCode) && count($area)) {
            $address = "{$area['province']}{$area['city']}{$area['district']}";
        }
        if (is_numeric($salesID)) {
            // 纠正线索来源
            if (1 == $salesID || ($salesID >= 201 && $salesID < 9000)) {
                $from = (string)FeishuCallingCard::query()
                    ->where('id', $salesID)
                    ->value('realname');
            } else if ($salesID > 0) {
                // 计算自定义来源
                $from = XiaokeService::getSourceByDepartment(
                    (string)FeishuCallingCard::query()
                        ->where('id', $salesID)
                        ->value('departmentName'), $salesName
                );
            }
            if (!strlen($from)) {
                $from = '夸父名片';
            }
        } else if ('u' === mb_substr($salesID, 0, 1)) {
            $from   = '门店推荐';
            $remark .= "夸父商家手机:{$invitorMobile}";
        }
        $interactiveChannel = static::interactiveChannel($interactiveChannel, $salesName);
        $params = [
            'clueInfo' => [
                's_clue_name'              => [$customerName], // 客户名称
                's_mobile_phone'           => [$customerPhone], // 手机
                's_remark'                 => [$remarkPrefix . $remark], // 备注
                's_create_time'            => [date('Y-m-d H:i:s')], // 创建时间
                'c_huodeshijian'           => [date('Y-m-d H:i:s')], // 获得时间
                'c_jiaohufangshi1'         => [$interactiveChannel], // 交互方式
                'c_xiansuolaiyuan24'       => [$from], // 线索来源
                'c_xiangxidizhi1'          => [$address],
                'c_kuafumingpianbianhao'   => [$salesID],
                'c_kuafumingpianmingcheng' => [$salesName],
//                's_owner'                  => [$owner],
            ],
            'wid'      => self::DEFAULT_WID_ID,
        ];

        if (strlen($areaCode)) {
            $params['clueInfo']['s_location'] = [$areaCode . '@#'];
        }
        $content = "客户名称：{$customerName}" . PHP_EOL;
        if (in_array($salesID, config('calling-cards.shijia.cardIds'))) {
            // 时嘉线索正常
            $content .= "客户手机：{$customerPhone}" . PHP_EOL;
        } else {
            // 夸父线索隐藏
            $content .= "客户手机：" . mb_substr($customerPhone, 0, 3) . '****' . mb_substr($customerPhone, 7) . PHP_EOL;
        }
        if (is_numeric($salesID)) {
            $content .= "推荐人名片ID：{$salesID}" . PHP_EOL;
            $content .= "推荐人：{$salesName}" . PHP_EOL;
        } else if ('u' === mb_substr($salesID, 0, 1)) {
            $content .= "门店手机：{$invitorMobile}" . PHP_EOL;
            $content .= "加盟商姓名：{$salesName}" . PHP_EOL;
        }
        if (strlen($areaCode)) {
            $content .= "城市：{$area['province']}{$area['city']}{$area['district']}" . PHP_EOL;
        }
        if (strlen($address)) {
            $content .= "地址：{$address}" . PHP_EOL;
        }
        $content .= "线索来源：{$from}\n";
        if (strlen($remark)) {
            $content .= "备注：{$remark}\n";
        }
        $content .= "填表时间：" . date('Y-m-d H:i:s') . PHP_EOL;
        $content .= '-------------------' . PHP_EOL;
        $s       = $this->freekerCurl("/api/1_0/xiaoke/clue/create", $params);
        if (!isset($s['code']['errcode']) || $s['code']['errcode'] != 0) {
            $atUsers = [];
            // 针对"入参不合法"重试
            $msg = $s['code']['errmsg'] ?? "";
            if ($msg == "入参不合法") {
                unset($params['clueInfo']['s_location']);
                $params['clueInfo']['c_xiangxidizhi1'] = ["{$area['province']}{$area['city']}{$area['district']}"];
                $s                                     = $this->freekerCurl("/api/1_0/xiaoke/clue/create", $params);
                if (!isset($s['code']['errcode']) || $s['code']['errcode'] != 0) {
                    // 重试失败
                    $msg     = $s['code']['errmsg'] ?? "";
                    $content .= '销氪新增线索重试失败' . PHP_EOL;
                    $content .= "失败原因：{$msg}" . PHP_EOL;
                    if (in_array($salesID, config('calling-cards.shijia.cardIds'))) {
                        $atUsers = config('calling-cards.shijia.clue.atUsers');
                    } else {
                        $atUsers = config('calling-cards.kuafu.clue.atUsers');
                    }
                    static::larkNotify($salesID, '创建线索失败', $content, $atUsers);
                    return self::returnData(false, $msg);
                } else {
                    // 重试成功
                }
            } else {
                // 针对重复线索
                $config = (string)ConfigModel::query()
                    ->where('module', 'callingCards')
                    ->where('name', 'duplicateClueText')
                    ->value('value');
                $arr = (array)(strlen($config) ? json_decode($config, true) : []);
                if (in_array($msg, $arr)) {

                    // 夸父炸串公司官方抖音B号 的线索。库里上一条线索手机号，与当前相差24小时内，不做推送
                    if ($salesID == 888) {
                        $lastClue = FeishuCallingCardFranchiseeClue::query()->where('mobile', $customerPhone)->orderByDesc('id')->first();
                        if ($lastClue && $lastClue->createdAt->timestamp - time() < 86400) {
                            Log::info("repeat 888 clue: {$customerPhone}");
                            return self::returnData(true, '夸父炸串公司官方抖音B号，一天内重复线索');
                        }
                    }

                    $clueId = (string)FeishuCallingCardFranchiseeClue::query()
                        ->where("mobile", $customerPhone)
                        ->where("clueId", "!=", "")
                        ->value("clueId");
                    if (strlen($clueId) > 0) {
                        $addClueLogParams = [
                            'key'     => $clueId,
                            'wid'     => self::DEFAULT_WID_ID,
                            'content' => "用户催办"
                        ];
                        $logResult        = $this->freekerCurl("/api/1_0/xiaoke/logs/addClueLog", $addClueLogParams);
                        $result           = $logResult['code']['errmsg'] ?? json_encode($logResult, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
                        $content          .= "跟进线索结果：{$result}\n-------------------\n";
                    }
                    if (in_array($salesID, config('calling-cards.shijia.cardIds'))) {
                        $atUsers = config('calling-cards.shijia.clue.atUsers');
                    } else {
                        $atUsers = config('calling-cards.kuafu.clue.atUsers');
                    }
                    // 给蓝兔发消息
                    SendFs::newRobot(SendFs::ROBOT_LANTU_CLUE)
                        ->setTitleContent('重复线索提醒', trim($content) . "\n\n原始手机：{$customerPhone}")
                        ->send();
                }

                // 失败
                $content .= '销氪新增线索失败' . PHP_EOL;
                $content .= "失败原因：{$msg}" . PHP_EOL;
                static::larkNotify($salesID, '创建线索失败', $content, $atUsers);
                return self::returnData(false, $msg);
            }
        }

        // 成功
        $content .= '销氪新增线索成功！' . PHP_EOL;

        // 线索
        $clueKey = $s['data']['key'] ?? '';
        // 变更所属人
        try {
            $owner = XiaokeService::getOwerByDepartmentName($departmentName, $salesName, $area);
        } catch (\Exception $exception) {
            $owner = self::DEFAULT_WID_ID;
        }

        $res = $this->changeOwner((int)$owner, $clueKey);
        if (!isset($res['code']['errcode']) || $res['code']['errcode'] != 0) {
            $content .= '变更所属人失败，请手动指派！所属人 ID：' . $owner . PHP_EOL;
        }
        static::larkNotify($salesID, '加盟申请', $content);
        return self::returnData(true, '', ['key' => $clueKey]);
    }

    /**
     * 发送飞书消息
     * @param string $cardId 例如：1、u1s4
     * @param string $title
     * @param string $content
     * @param array $atUsers
     * @return mixed
     */
    protected static function larkNotify(string $cardId, string $title, string $content, array $atUsers = [])
    {
        try {
            static::areaRobot($title, $content);
        } catch (\Exception $exception) {}
        if (in_array((int)$cardId, config('calling-cards.shijia.cardIds'))) {
            $builder = SendFs::newRobot(SendFs::ROBOT_SHIJIA);
        } else {
            $builder = SendFs::newRobot(SendFs::ROBOT_JOIN);
        }
        $builder->setTitleContent($title, $content);
        foreach ($atUsers as $userId) {
            $builder->setAtUid($userId);
        }
        return $builder->send();
    }

    /**
     * 根据消息来源的省份名字，去配置获取机器人配置，发给省区群
     * @param string $title
     * @param string $content
     * @return void
     */
    protected static function areaRobot(string $title, string $content)
    {
        $config = ConfigService::areaRobots();
        if (!count($config)) {
            return;
        }
        $prefix = ['城市：', '地址：'];
        $messageLines = explode("\n", $content);
        $area = ''; // 可能匹配不上城市
        // 优先根据城市、地址来获取地区信息
        foreach ($messageLines as $messageLine) {
            foreach ($prefix as $pp) {
                if (Str::startsWith($messageLine, $pp)) {
                    $area = mb_substr($messageLine, mb_strlen($pp));
                    break 2;
                }
            }
        }
        // 其次根据备注信息获取地区信息，
        $prefix = ['备注：留言内容：', '备注：'];
        if ('' === $area) {
            foreach ($messageLines as $messageLine) {
                foreach ($prefix as $pp) {
                    if (Str::startsWith($messageLine, $pp)) {
                        $area = mb_substr($messageLine, mb_strlen($pp));
                        break 2;
                    }
                }
            }
        }
        if ('' === $area) {
            // 没有拿到地区信息
            return;
        }
        foreach ($config as $k => $v) {
            if (Str::startsWith($area, $k)) {
                SendFs::newRobot(SendFs::ROBOT_JOIN)
                    ->coverConfig($v['webhook'], $v['sign'])
                    ->setTitleContent($title, $content)
                    ->send();
                return;
            }
        }
    }

    protected static function interactiveChannel(string $interactiveChannel, string $salesName): string
    {
        $realName = XiaokeService::getRealName($salesName);
        $staff = FeishuCallingCardInvestmentEmployeeModel::allStaff();
        foreach ($staff as $v) {
            if ($v['name'] == $realName && strlen(trim($v['interactiveChannel']))) {
                return $v['interactiveChannel'];
            }
        }
        return $interactiveChannel;
    }

    /**
     * 线索字段列表
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function clueColumn(): array
    {
        $params = [
            'wid' => self::DEFAULT_WID_ID,
        ];

        return $this->freekerCurl("/api/1_0/xiaoke/fields/clue", $params);
    }

    /**
     * 变更线索
     * @param int $owner
     * @param string $key
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function changeOwner(int $owner, string $key): array
    {
        $params = [
            'owner' => $owner, // 新所属人
            'key'   => $key, // 线索
            'wid'   => self::DEFAULT_WID_ID, // 操作用户
        ];

        return $this->freekerCurl("/api/1_0/xiaoke/clue/changeOwner", $params);
    }

    /**
     * 获取accessToken
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    private function getAccessToken(): string
    {
        if (Cache::has(self::ACCESS_TOKEN)) {
            return Cache::get(self::ACCESS_TOKEN);
        }

        $params = [
            'grant_type'    => 'client_credentials',
            'client_id'     => self::CLIENT_ID,
            'client_secret' => self::CLIENT_SECRET,
        ];

        $s = $this->freekerCurl("/fuwu/b/oauth2/token", $params, RequestOptions::FORM_PARAMS);

        if (!isset($s['expires_in']) || !isset($s['access_token'])) {
            throw new \Exception('Freeker获取accessToken失败：' . json_encode($s, JSON_UNESCAPED_UNICODE));
        }

        if ($s['expires_in'] >= 5) {
            Cache::put(self::ACCESS_TOKEN, $s['access_token'], $s['expires_in'] - 5);
        }

        return $s['access_token'];
    }


    /**
     * Freeker基类Curl
     * @param string $path
     * @param array $params
     * @param string $requestType
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    private function freekerCurl(string $path, array $params, string $requestType = RequestOptions::JSON): array
    {
        $uri = "https://dopen.weimob.com" . $path;
        if ($path != '/fuwu/b/oauth2/token') {
            $uri .= "?accesstoken=" . $this->getAccessToken();
        }

        $response = (new Client([
            RequestOptions::TIMEOUT     => 8,
            RequestOptions::HTTP_ERRORS => false,
            RequestOptions::VERIFY      => false,
        ]))->post($uri, [$requestType => $params]);
        $content  = $response->getBody()->getContents();
        Log::info("请求销氪接口：{$path},参数:" . json_encode($params, JSON_UNESCAPED_UNICODE) . ",返回内容:{$content}");
        return json_decode($content, true) ?? [];
    }

    public function clueDetail(string $propertyKey)
    {
        return $this->freekerCurl("/api/1_0/xiaoke/fields/clueDetail", [
            'wid'         => static::DEFAULT_WID_ID,
            'propertyKey' => $propertyKey,
        ]);
    }
}
